package org.zoomdev.zoom.validator;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 快速验证场景
 */
public final class FastValidator {

    private FastValidator() {

    }


    /**
     * 验证字符串是否符合指定的正则表达式
     *
     * @param <T>     对象类型
     * @param obj     要验证的对象（必须为字符串类型）
     * @param pattern 正则表达式模式
     * @param message 验证失败时的错误消息
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或不符合正则表达式
     *                           <p>
     *                           示例：
     *                           String email = FastValidator.regexp(inputEmail, "^\\w+@\\w+\\.\\w+$", "邮箱格式不正确");
     */
    public static <T> T regexp(T obj, String pattern, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        if (!Pattern.matches(pattern, obj.toString())) {
            throw new ValidateException(message);
        }
        return obj;
    }


    /**
     * 验证字符串是否符合指定的日期格式
     *
     * @param <T>     对象类型
     * @param obj     要验证的对象（必须为字符串类型）
     * @param format  日期格式（如"yyyy-MM-dd"）
     * @param message 验证失败时的错误消息
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或不符合日期格式
     *                           <p>
     *                           示例：
     *                           String birthDate = FastValidator.dateFormat(inputDate, "yyyy-MM-dd", "日期格式应为YYYY-MM-DD");
     */
    public static <T> T dateFormat(T obj, String format, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setLenient(false); // 严格模式
        try {
            sdf.parse(obj.toString());
        } catch (ParseException e) {
            throw new ValidateException(message);
        }
        return obj;
    }

    /**
     * 验证是否是字符串，且长度是否符合标准
     *
     * @param obj     要验证的对象
     * @param len     期望的精确长度
     * @param message 验证失败时的错误消息
     * @param <T>     对象类型
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或长度不匹配
     */
    public static <T> T length(T obj, int len, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        if (((CharSequence) obj).length() != len) {
            throw new ValidateException(message);
        }
        return obj;
    }

    /**
     * 验证是否是字符串，且长度是否符合标准范围
     *
     * @param obj       要验证的对象
     * @param minLength 最小长度（包含）
     * @param maxLength 最大长度（包含）
     * @param message   验证失败时的错误消息
     * @param <T>       对象类型
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或长度不在范围内
     */
    public static <T> T length(T obj, int minLength, int maxLength, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        int length = ((CharSequence) obj).length();
        if (length < minLength || length > maxLength) {
            throw new ValidateException(message);
        }
        return obj;
    }

    /**
     * 验证是否是字符串，且长度是否小于等于maxLength
     *
     * @param obj       要验证的对象
     * @param maxLength 最大长度（包含）
     * @param message   验证失败时的错误消息
     * @param <T>       对象类型
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或长度超过限制
     */
    public static <T> T lengthShorterThan(T obj, int maxLength, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        if (((CharSequence) obj).length() > maxLength) {
            throw new ValidateException(message);
        }
        return obj;
    }

    /**
     * 验证是否是字符串，且长度是否大于等于minLength
     *
     * @param obj       要验证的对象
     * @param minLength 最小长度（包含）
     * @param message   验证失败时的错误消息
     * @param <T>       对象类型
     * @return 验证通过的对象本身
     * @throws ValidateException 如果对象不是字符串或长度不足
     */
    public static <T> T lengthLongerThan(T obj, int minLength, String message) {
        notNull(obj, message);
        if (!(obj instanceof CharSequence)) {
            throw new ValidateException("必须是字符串类型");
        }
        if (((CharSequence) obj).length() < minLength) {
            throw new ValidateException(message);
        }
        return obj;
    }

    /**
     * 验证对象是否为非null值
     *
     * @param <T>     对象类型
     * @param obj     要验证的对象
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原对象
     * @throws ValidateException 当对象为null时抛出
     *                           <p>
     *                           示例：
     *                           User user = FastValidator.notNull(userObj, "用户信息不能为空");
     */
    public static <T> T notNull(T obj, String message) {
        if (obj == null)
            throw new ValidateException(message);
        return obj;
    }

    /**
     * 验证字符串是否为非空（非null且长度大于0）
     *
     * @param obj     要验证的字符串
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原字符串
     * @throws ValidateException 当字符串为null或空字符串时抛出
     *                           <p>
     *                           注：仅检查null和空字符串("")，不处理空白字符
     *                           <p>
     *                           示例：
     *                           String id = FastValidator.notEmpty(userId, "用户ID不能为空");
     */
    public static String notEmpty(String obj, String message) {
        if (StringUtils.isEmpty(obj))
            throw new ValidateException(message);
        return obj;
    }

    /**
     * 验证字符串是否为非空白（非null且包含非空白字符）
     *
     * @param obj     要验证的字符串
     * @param message 验证失败时抛出的异常信息
     * @return 去除首尾空白后的字符串
     * @throws ValidateException 当字符串为null、空字符串或纯空白字符时抛出
     *                           <p>
     *                           注：会自动去除字符串首尾的空白字符
     *                           <p>
     *                           示例：
     *                           String name = FastValidator.notBlank(username, "用户名不能为空或纯空格");
     */
    public static String notBlank(String obj, String message) {
        if (StringUtils.isBlank(obj))
            throw new ValidateException(message);
        return StringUtils.trim(obj);
    }

    /**
     * 检查对象是否为null或空
     * 支持String、Collection、Map、数组等类型
     *
     * @param obj     要检查的对象
     * @param message 错误消息
     * @return 非空对象本身
     * @throws ValidateException 如果对象为null或空
     */
    public static <T> T notEmpty(T obj, String message) {
        if (obj == null) {
            throw new ValidateException(message);
        }

        if (obj instanceof CharSequence) {
            if (((CharSequence) obj).length() == 0) {
                throw new ValidateException(message);
            }
        } else if (obj instanceof Collection) {
            if (((Collection<?>) obj).isEmpty()) {
                throw new ValidateException(message);
            }
        } else if (obj instanceof Map) {
            if (((Map<?, ?>) obj).isEmpty()) {
                throw new ValidateException(message);
            }
        } else if (obj.getClass().isArray()) {
            if (java.lang.reflect.Array.getLength(obj) == 0) {
                throw new ValidateException(message);
            }
        }

        return obj;
    }

    /**
     * 检查字符串是否为null或空白
     * 如果对象不是String类型，会先调用toString()
     *
     * @param obj     要检查的对象
     * @param message 错误消息
     * @return 去除了前后空格的字符串
     * @throws ValidateException 如果字符串为null或空白
     */
    public static String notBlank(Object obj, String message) {
        notNull(obj, message);
        String str = obj.toString();
        if (StringUtils.isBlank(str)) {
            throw new ValidateException(message);
        }

        return StringUtils.trim(str);
    }


    /**
     * 验证集合是否为非空（非null且至少包含一个元素）
     *
     * @param <T>        集合类型，必须实现Collection接口
     * @param collection 要验证的集合
     * @param message    验证失败时抛出的异常信息
     * @return 验证通过的原集合
     * @throws ValidateException 当集合为null或空集合时抛出
     *                           <p>
     *                           示例：
     *                           List<String> names = FastValidator.notEmpty(nameList, "姓名列表不能为空");
     *                           Set<Long> ids = FastValidator.notEmpty(idSet, "ID集合不能为空");
     */
    public static <T extends Collection<?>> T notEmpty(T collection, String message) {
        if (collection == null || collection.isEmpty())
            throw new ValidateException(message);
        return collection;
    }

    /**
     * 验证Map是否为非空（非null且至少包含一个键值对）
     *
     * @param <T>     Map类型，必须实现Map接口
     * @param map     要验证的Map
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原Map
     * @throws ValidateException 当Map为null或空Map时抛出
     *                           <p>
     *                           示例：
     *                           Map<String, Object> params = FastValidator.notEmpty(paramMap, "参数Map不能为空");
     */
    public static <T extends Map<?, ?>> T notEmpty(T map, String message) {
        if (map == null || map.isEmpty())
            throw new ValidateException(message);
        return map;
    }

    /**
     * 验证数组是否为非空（非null且至少包含一个元素）
     *
     * @param <T>     数组元素类型
     * @param array   要验证的数组
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原数组
     * @throws ValidateException 当数组为null或空数组时抛出
     *                           <p>
     *                           示例：
     *                           String[] tags = FastValidator.notEmpty(tagArray, "标签数组不能为空");
     *                           int[] values = FastValidator.notEmpty(valueArray, "数值数组不能为空");
     */
    public static <T> T[] notEmpty(T[] array, String message) {
        if (array == null || array.length == 0)
            throw new ValidateException(message);
        return array;
    }

// ========== 数值验证方法 ========== //

    /**
     * 验证整数是否为正数（大于0）
     *
     * @param number  要验证的整数值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于等于0时抛出
     *                           <p>
     *                           示例：
     *                           int age = FastValidator.positive(userAge, "年龄必须是正整数");
     */
    public static int positive(int number, String message) {
        if (number <= 0)
            throw new ValidateException(message);
        return number;
    }

    /**
     * 验证长整型是否为正数（大于0）
     *
     * @param number  要验证的长整型值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于等于0时抛出
     *                           <p>
     *                           示例：
     *                           long price = FastValidator.positive(itemPrice, "商品价格必须大于0");
     */
    public static long positive(long number, String message) {
        if (number <= 0)
            throw new ValidateException(message);
        return number;
    }

    /**
     * 验证双精度浮点数是否为正数（大于0）
     *
     * @param number  要验证的双精度值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于等于0时抛出
     *                           <p>
     *                           示例：
     *                           double score = FastValidator.positive(testScore, "考试分数必须大于0");
     */
    public static double positive(double number, String message) {
        if (number <= 0)
            throw new ValidateException(message);
        return number;
    }

    /**
     * 验证整数是否为非负数（大于等于0）
     *
     * @param number  要验证的整数值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于0时抛出
     *                           <p>
     *                           示例：
     *                           int count = FastValidator.nonNegative(stockCount, "库存数量不能为负数");
     */
    public static int nonNegative(int number, String message) {
        if (number < 0)
            throw new ValidateException(message);
        return number;
    }

    /**
     * 验证长整型是否为非负数（大于等于0）
     *
     * @param number  要验证的长整型值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于0时抛出
     *                           <p>
     *                           示例：
     *                           long distance = FastValidator.nonNegative(routeDistance, "距离不能为负数");
     */
    public static long nonNegative(long number, String message) {
        if (number < 0)
            throw new ValidateException(message);
        return number;
    }

    /**
     * 验证双精度浮点数是否为非负数（大于等于0）
     *
     * @param number  要验证的双精度值
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException 当数值小于0时抛出
     *                           <p>
     *                           示例：
     *                           double weight = FastValidator.nonNegative(productWeight, "产品重量不能为负数");
     */
    public static double nonNegative(double number, String message) {
        if (number < 0)
            throw new ValidateException(message);
        return number;
    }

    // 范围验证方法

    /**
     * 验证整数值是否在指定范围内[min, max]（包含边界值）
     *
     * @param number  要验证的整数值
     * @param min     允许的最小值（包含）
     * @param max     允许的最大值（包含）
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException        当数值超出范围时抛出
     * @throws IllegalArgumentException 当min > max时抛出
     *                                  <p>
     *                                  示例：
     *                                  int age = FastValidator.inRange(userAge, 18, 60, "年龄必须在18-60岁之间");
     */
    public static int inRange(int number, int min, int max, String message) {
        if (min > max) {
            throw new IllegalArgumentException("最小值不能大于最大值");
        }
        if (number < min || number > max) {
            throw new ValidateException(message);
        }
        return number;
    }

    /**
     * 验证长整型值是否在指定范围内[min, max]（包含边界值）
     *
     * @param number  要验证的长整型值
     * @param min     允许的最小值（包含）
     * @param max     允许的最大值（包含）
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException        当数值超出范围时抛出
     * @throws IllegalArgumentException 当min > max时抛出
     *                                  <p>
     *                                  示例：
     *                                  long price = FastValidator.inRange(itemPrice, 100L, 10000L, "价格必须在100-10000之间");
     */
    public static long inRange(long number, long min, long max, String message) {
        if (min > max) {
            throw new IllegalArgumentException("最小值不能大于最大值");
        }
        if (number < min || number > max) {
            throw new ValidateException(message);
        }
        return number;
    }

    /**
     * 验证双精度值是否在指定范围内[min, max]（包含边界值）
     *
     * @param number  要验证的双精度值
     * @param min     允许的最小值（包含）
     * @param max     允许的最大值（包含）
     * @param message 验证失败时抛出的异常信息
     * @return 验证通过的原始值
     * @throws ValidateException        当数值超出范围时抛出
     * @throws IllegalArgumentException 当min > max时抛出
     *                                  <p>
     *                                  示例：
     *                                  double score = FastValidator.inRange(testScore, 0.0, 100.0, "分数必须在0-100分之间");
     */
    public static double inRange(double number, double min, double max, String message) {
        if (min > max) {
            throw new IllegalArgumentException("最小值不能大于最大值");
        }
        if (number < min || number > max) {
            throw new ValidateException(message);
        }
        return number;
    }

// ========== 状态验证方法 ========== //

    /**
     * 验证业务状态是否满足条件
     *
     * @param condition 要验证的条件表达式
     * @param message   验证失败时抛出的异常信息
     * @return 总是返回null（用于void方法链式调用）
     * @throws ValidateException 当条件不满足时抛出
     *                           <p>
     *                           示例：
     *                           FastValidator.checkState(user.isActive(), "用户账号未激活");
     */
    public static <T> T checkState(boolean condition, String message) {
        if (!condition) {
            throw new ValidateException(message);
        }
        return null;
    }

    /**
     * 验证业务状态是否满足条件（带返回值版本）
     *
     * @param condition   要验证的条件表达式
     * @param message     验证失败时抛出的异常信息
     * @param returnValue 验证通过时返回的值
     * @return 验证通过时返回指定值
     * @throws ValidateException 当条件不满足时抛出
     *                           <p>
     *                           示例：
     *                           User admin = FastValidator.checkState(isAdmin, "需要管理员权限", adminUser);
     */
    public static <T> T checkState(boolean condition, String message, T returnValue) {
        if (!condition) {
            throw new ValidateException(message);
        }
        return returnValue;
    }

// ========== 对象验证方法 ========== //

    /**
     * 使用自定义验证器验证对象
     *
     * @param obj       要验证的对象
     * @param validator 自定义验证器实例
     * @return 验证通过的原对象
     * @throws ValidateException 当验证不通过时抛出（包含验证器的错误消息）
     *                           <p>
     *                           示例：
     *                           User user = FastValidator.validate(inputUser, new UserValidator());
     */
    public static <T> T validate(T obj, Validator validator) {
        if (!validator.isValid(obj)) {
            throw new ValidateException(validator.getMessage());
        }
        return obj;
    }


    public static <T> T validate(T obj) {
        Validators.validate(obj);
        return obj;
    }


}
